package com.mzj.saas.mservice.aio.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.mzj.saas.commons.*;
import com.mzj.saas.commons.enums.ChargeTypeEnum;
import com.mzj.saas.commons.enums.PaymentTypeEnum;
import com.mzj.saas.commons.enums.RrentBillPaymentStatusTypeEnum;
import com.mzj.saas.commons.util.Base64Utils;
import com.mzj.saas.commons.util.ConvertUtils;
import com.mzj.saas.commons.util.DataUtils;
import com.mzj.saas.config.pay.PayConfig;
import com.mzj.saas.mservice.aio.entity.Device;
import com.mzj.saas.mservice.aio.repository.DeviceRepository;
import com.mzj.saas.mservice.aio.vo.*;
import com.mzj.saas.mservice.auth.service.InitFaceVerifyService;
import com.mzj.saas.mservice.auth.vo.AuthenticationVo;
import com.mzj.saas.mservice.bill.entity.ExpenseBill;
import com.mzj.saas.mservice.bill.entity.RentBill;
import com.mzj.saas.mservice.bill.repository.ExpenseBillRepository;
import com.mzj.saas.mservice.bill.repository.RentBillRepository;
import com.mzj.saas.mservice.bill.vo.PaymentBillRedisVo;
import com.mzj.saas.mservice.eligible.entity.DepartmentHierarchy;
import com.mzj.saas.mservice.eligible.service.DepartmentHierarchyService;
import com.mzj.saas.mservice.face.service.FaceThanService;
import com.mzj.saas.mservice.house.entity.Cohabit;
import com.mzj.saas.mservice.house.entity.House;
import com.mzj.saas.mservice.house.repository.HouseRepository;
import com.mzj.saas.mservice.house.service.HouseService;
import com.mzj.saas.mservice.house.vo.HouseInfoVO;
import com.mzj.saas.mservice.lock.Repository.SmartLockAuthRepository;
import com.mzj.saas.mservice.lock.Repository.SmartLockRepository;
import com.mzj.saas.mservice.lock.entity.SmartLock;
import com.mzj.saas.mservice.lock.entity.SmartLockAuth;
import com.mzj.saas.mservice.lock.entity.SmartLockFace;
import com.mzj.saas.mservice.lock.service.LockAppService;
import com.mzj.saas.mservice.oss.service.OSSService;
import com.mzj.saas.mservice.property.entity.CommunityHouseUser;
import com.mzj.saas.mservice.property.entity.EstateExpenseBill;
import com.mzj.saas.mservice.property.entity.EstateRentBill;
import com.mzj.saas.mservice.property.repository.CommunityHouseUserRepository;
import com.mzj.saas.mservice.property.repository.EstateExpenseBillRepository;
import com.mzj.saas.mservice.property.repository.EstateRentBillRepository;
import com.mzj.saas.mservice.property.service.CommunityHouseUserService;
import com.mzj.saas.mservice.property.vo.RepairsHouse;
import com.mzj.saas.mservice.sys.entity.AppUser;
import com.mzj.saas.mservice.sys.entity.WechatAccount;
import com.mzj.saas.mservice.sys.repository.AppUserRepository;
import com.mzj.saas.mservice.sys.repository.WechatAccountRepository;
import com.mzj.saas.redis.RedisService;
import com.mzj.saas.sdk.pay.alipay.AliPayRequest;
import com.mzj.saas.sdk.pay.vo.AliPay;
import com.mzj.saas.sdk.pay.vo.WxPay;
import com.mzj.saas.sdk.pay.wxpay.WxPayRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SingleColumnRowMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class AioService {
    private static final Logger log = LoggerFactory.getLogger(AioService.class);

    @Autowired
    private AppUserRepository appUserRepository;
    @Autowired
    private RedisService redisService;
    @Autowired
    @Qualifier("stringRedisTemplate")
    private StringRedisTemplate redisTemplate;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private LockAppService lockAppService;
    @Autowired
    private FaceThanService faceThanService;
    @Autowired
    private HouseService houseService;
    @Autowired
    private RentBillRepository rentBillRepository;
    @Autowired
    private ExpenseBillRepository expenseBillRepository;
    @Autowired
    private WechatAccountRepository wechatAccountRepository;
    @Autowired
    private DepartmentHierarchyService departmentHierarchyService;
    @Autowired
    private PayConfig payConfig;
    @Autowired
    private EstateRentBillRepository estateRentBillRepository;
    @Autowired
    private EstateExpenseBillRepository estateExpenseBillRepository;
    @Autowired
    private OSSService ossService;
    @Autowired
    private DeviceRepository deviceRepository;


    @Autowired
    private CommunityHouseUserRepository communityHouseUserRepository;

    @Autowired
    private CommunityHouseUserService communityHouseUserService;

    @Autowired
    private HouseRepository houseRepository;

    @Autowired
    private SmartLockRepository smartLockRepository;
    @Autowired
    private SmartLockAuthRepository smartLockAuthRepository;
    @Autowired
    private InitFaceVerifyService initFaceVerifyService;

    public ResultBean<Object> verifyPwd(String pwd) {
        try {
            if (StringUtils.isBlank(pwd)) {
                return ResultBean.failedResultOfParamWithMsg("密码为空");
            }

            Boolean flag = false;// true 通过,false 不通过
            String value = redisService.getValue("aio.pwd");
            if (value.equals(pwd)) {
                flag = true;
            }

            return ResultBean.successfulResult(flag);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> houseVerifyUser(UserVO vo) {
        try {
            log.info("AioService houseVerifyUser ,vo={}", JSON.toJSONString(vo));
            String name = vo.getName();
            String cardNumber = vo.getCardNumber();
            if (StringUtils.isBlank(name)) {
                return ResultBean.failedResultOfParamWithMsg("姓名为空");
            }
            if (StringUtils.isBlank(cardNumber)) {
                return ResultBean.failedResultOfParamWithMsg("身份证号码为空");
            }

            Integer flag = null;// 标识：1无人员信息，2有人员信息
            String houseSql = "SELECT u.house_id AS houseId \n" +
                    "FROM saas_house_eligible_apply a\n" +
                    "JOIN saas_house_match_user u ON a.id = u.apply_id \n" +
                    "WHERE a.card_number = ? AND u.status = 1 \n" +
                    "UNION \n" +
                    "SELECT u.house_id AS houseId \n" +
                    "FROM saas_house_eligible_apply_cohabit c\n" +
                    "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                    "WHERE c.card_number = ? AND u.status = 1\n" +
                    "UNION\n" +
                    "SELECT u.community_house_id AS houseId \n" +
                    "FROM saas_community_house_user u\n" +
                    "JOIN saas_smart_lock l ON u.community_house_id = l.house_id\n" +
                    "WHERE u.card_number = ? AND u.status = 1 " +
                    "UNION\n" +
                    "SELECT u.community_house_id AS houseId \n" +
                    "FROM saas_community_house_user u\n" +
                    "LEFT JOIN saas_app_user us ON us.phone = u.mobile\n" +
                    "JOIN saas_smart_lock l ON u.community_house_id = l.house_id\n" +
                    "WHERE us.card_number = ? AND u.status = 1 ";
            List<Object> args = new ArrayList<>();
            args.add(cardNumber);
            args.add(cardNumber);
            args.add(cardNumber);
            args.add(cardNumber);

            List<String> houseIdList = jdbcTemplate.query(houseSql, new SingleColumnRowMapper<>(String.class), args.toArray());
            if (CollectionUtils.isEmpty(houseIdList)) {
                flag = 1;
            } else {
                flag = 2;
            }
            log.info("AioService 身份验证, 结果={}", flag == 1 ? "无人员信息" : "有人员信息");
            return ResultBean.successfulResult(flag);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> faceCompare(UserVO vo) {
        File file = null;
        try {
            log.info("AioService faceCompare 人脸识别, cardNumber={}", vo.getCardNumber());

            if (StringUtils.isBlank(vo.getCardNumber())) {
                return ResultBean.failedResultOfParamWithMsg("身份证号码为空");
            }
            if (StringUtils.isBlank(vo.getFaceData())) {
                return ResultBean.failedResultOfParamWithMsg("人脸识别数据为空");
            }

            Boolean flag = false;
            if (!StringUtils.isBlank(vo.getCardData())) {
                log.info("AioService faceCompare 有身份证人脸比对");
                /*FaceCompare faceCompare = new FaceCompare();
                faceCompare.setCardNumber(vo.getCardNumber());
                faceCompare.setFaceData(vo.getFaceData());
                faceCompare.setCardData(vo.getCardData());
                faceCompare.setCreateTime(new Date());
                faceCompareRepository.save(faceCompare);*/

                flag = faceThanService.FaceCompareFace(vo.getFaceData(), vo.getCardData());
            } else {
                /**
                 * 1, 先对比实人认证信息
                 * 2， 当条件1为 false 时 查询公租房同住人获得人脸，再次对比
                 * 3. 当条件2为 false 时 查询非公租房同住人获得人脸，再次对比
                 * 4.当以上条件都不满足时， 开锁失败
                 */
                log.info("AioService faceCompare 无身份证人脸比对");
                // 根据身份证号码查询已认证的用户
                String appUserSql = "select u.* from  saas_app_user u where u.certification_status=1 and u.status = 1 and u.card_number=?";

                List<AppUser> appUserList = jdbcTemplate.query(appUserSql, new BeanPropertyRowMapper<>(AppUser.class), vo.getCardNumber());

                if (appUserList.isEmpty()) {
                    log.error("AioService faceCompare 未找到实名认证信息");
                }
                if (!appUserList.isEmpty()) {
                    AppUser appUser = appUserList.get(0);
                    String facePic = appUser.getFacePic();
                    if (StringUtils.isBlank(facePic)) {
                        log.error("AioService faceCompare 认证人脸照片不存在");
                    }
                    if (StringUtils.isNotBlank(facePic)) {
                        file = ossService.getObjectFile("", facePic);
                        // file转base64
                        FileInputStream inputFile = new FileInputStream(file);
                        byte[] buffer = new byte[(int) file.length()];
                        inputFile.read(buffer);
                        inputFile.close();
                        String cohabitEncode = Base64Utils.encode(buffer);

                        /*FaceCompare faceCompare = new FaceCompare();
                        faceCompare.setCardNumber(vo.getCardNumber());
                        faceCompare.setFaceData(vo.getFaceData());
                        faceCompare.setCardData(cohabitEncode);
                        faceCompare.setCreateTime(new Date());
                        faceCompareRepository.save(faceCompare);*/

                        flag = faceThanService.FaceCompareFace(vo.getFaceData(), cohabitEncode);
                    }
                }
                // 查询公租房同住人获得人脸，再次对比
                if (!flag) {
                    // 无身份证，与同住人人脸照比对
                    String sql = "SELECT c.* \n" +
                            "FROM saas_house_eligible_apply_cohabit c\n" +
                            "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                            "WHERE c.card_number = ? AND u.status = 1";
                    List<Cohabit> cohabitList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Cohabit.class), vo.getCardNumber());
                    if (cohabitList.isEmpty()) {
                        log.error("AioService faceCompare 未找到同住人信息");
                    }
                    if (!cohabitList.isEmpty()) {
                        Cohabit cohabit = cohabitList.get(0);
                        String facePic = cohabit.getFacePic();
                        if (StringUtils.isBlank(facePic)) {
                            log.error("AioService faceCompare 同住人人脸照片不存在");
                        }
                        if (StringUtils.isNotBlank(facePic)) {
                            file = ossService.getObjectFile("", facePic);
                            // file转base64
                            FileInputStream inputFile = new FileInputStream(file);
                            byte[] buffer = new byte[(int) file.length()];
                            inputFile.read(buffer);
                            inputFile.close();
                            String cohabitEncode = Base64Utils.encode(buffer);

                        /*FaceCompare faceCompare = new FaceCompare();
                        faceCompare.setCardNumber(vo.getCardNumber());
                        faceCompare.setFaceData(vo.getFaceData());
                        faceCompare.setCardData(cohabitEncode);
                        faceCompare.setCreateTime(new Date());
                        faceCompareRepository.save(faceCompare);*/

                            flag = faceThanService.FaceCompareFace(vo.getFaceData(), cohabitEncode);
                        }
                    }
                }
                // 查询非公租房同住人获得人脸，再次对比
                if (!flag) {

                    // 无身份证，与非公租房同住人人脸照比对
                    String sql = "SELECT u.* FROM  saas_community_house_user u where u.status=1 and u.card_number=? ORDER BY operator_time DESC";
                    List<CommunityHouseUser> houseUserList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(CommunityHouseUser.class), vo.getCardNumber());

                    if (houseUserList.isEmpty()) {
                        log.error("AioService faceCompare 未找到非公租房成员信息");
                    }
                    if (!houseUserList.isEmpty()) {
                        CommunityHouseUser houseUser = houseUserList.get(0);
                        String facePic = houseUser.getHumanFaceImage();
                        if (StringUtils.isBlank(facePic)) {
                            log.error("AioService faceCompare 非公租房成员人脸照片不存在");
                        }
                        if (StringUtils.isNotBlank(facePic)) {
                            file = ossService.getObjectFile("", facePic);
                            // file转base64
                            FileInputStream inputFile = new FileInputStream(file);
                            byte[] buffer = new byte[(int) file.length()];
                            inputFile.read(buffer);
                            inputFile.close();
                            String cohabitEncode = Base64Utils.encode(buffer);
                        /*FaceCompare faceCompare = new FaceCompare();
                        faceCompare.setCardNumber(vo.getCardNumber());
                        faceCompare.setFaceData(vo.getFaceData());
                        faceCompare.setCardData(cohabitEncode);
                        faceCompare.setCreateTime(new Date());
                        faceCompareRepository.save(faceCompare);*/

                            flag = faceThanService.FaceCompareFace(vo.getFaceData(), cohabitEncode);
                        }
                    }

                }

            }
            log.info("AioService 人脸比对结果, flag={}", flag);
            return ResultBean.successfulResult(flag);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        } finally {
            if (file != null) {
                file.delete();
            }
        }
    }

    public ResultBean<List<RepairsHouse>> houseList(UserVO vo) {
        try {
            log.info("AioService houseList vo = {}", JSON.toJSONString(vo));
            String cardNumber = vo.getCardNumber();
            if (StringUtils.isBlank(cardNumber)) {
                return ResultBean.failedResultOfParamWithMsg("身份证号码为空");
            }

            /*
             * 查询用户关联房屋
             * 公租房，锁已安装、已备案；非公租房，锁已安装
             */
            String houseSql = "SELECT u.house_id AS houseId \n" +
                    "FROM saas_house_eligible_apply a\n" +
                    "JOIN saas_house_match_user u ON a.id = u.apply_id\n" +
                    "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                    "JOIN saas_smart_lock l ON u.house_id = l.house_id\n" +
                    "WHERE a.card_number = ? AND u.status = 1 AND h.record_status = 1\n" +
                    "UNION\n" +
                    "SELECT u.house_id AS houseId \n" +
                    "FROM saas_house_eligible_apply_cohabit c\n" +
                    "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                    "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                    "JOIN saas_smart_lock l ON u.house_id = l.house_id\n" +
                    "WHERE c.card_number = ? AND u.status = 1 AND h.record_status = 1\n" +
                    "UNION\n" +
                    "SELECT u.community_house_id AS houseId \n" +
                    "FROM saas_community_house_user u\n" +
                    "JOIN saas_smart_lock l ON u.community_house_id = l.house_id\n" +
                    "WHERE u.card_number = ? AND u.status = 1 \n" +
                    "UNION\n" +
                    "SELECT u.community_house_id AS houseId \n" +
                    "FROM saas_community_house_user u\n" +
                    "LEFT JOIN saas_app_user us ON us.phone = u.mobile\n" +
                    "JOIN saas_smart_lock l ON u.community_house_id = l.house_id\n" +
                    "WHERE us.card_number = ? AND u.status = 1 ";
            List<Object> args = new ArrayList<>();
            args.add(cardNumber);
            args.add(cardNumber);
            args.add(cardNumber);
            args.add(cardNumber);
            List<String> houseIdList = jdbcTemplate.query(houseSql, new SingleColumnRowMapper<>(String.class), args.toArray());

            String houseQuery = "SELECT h.id AS house_id,case h.house_nature when 1 then 1 else 2 end AS house_type,case h.house_nature when 1 then '公租房' else '物业房产' end as houseTypeName, \n" +
                    "h.residence_community_id AS community_id,c.name AS community_name, h.building_num AS building_num, b.name AS building_num_name, h.unit, \n" +
                    "u.name AS unit_name, h.room_number,h.floor,h.owner_name as ownerName,h.owner_mobile as ownerMobile,h.org_id,h.house_property_id as housePropertyId FROM saas_house h \n" +
                    "LEFT JOIN saas_community c ON c.id = h.residence_community_id \n" +
                    "LEFT JOIN saas_community_build b ON b.id = h.building_num \n" +
                    "LEFT JOIN saas_community_build_unit u ON u.id = h.unit WHERE h.id in ";
            List<RepairsHouse> list = new ArrayList<>();
            if (!houseIdList.isEmpty()) {
                list = jdbcTemplate.query(houseQuery + SQLUtils.foreachIn(houseIdList.size()), new BeanPropertyRowMapper<>(RepairsHouse.class), houseIdList.toArray());
            }

            log.info("AioService 房屋列表, list={}", JSON.toJSONString(list));
            return ResultBean.successfulResult(list);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> lockAuth(AuthVO vo) {
        try {
            log.info("AioService lockAuth vo = {}", JSON.toJSONString(vo));
            if (vo.getHouseIds() == null || vo.getHouseIds().isEmpty()) {
                return ResultBean.failedResultOfParamWithMsg("房屋id为空");
            }
            if (vo.getType() == null) {
                return ResultBean.failedResultOfParamWithMsg("类型为空");
            }
            if (StringUtils.isBlank(vo.getCardNumber())) {
                return ResultBean.failedResultOfParamWithMsg("身份证号码为空");
            }
            if (vo.getType() == 2 && StringUtils.isBlank(vo.getFingerprint())) {
                return ResultBean.failedResultOfParamWithMsg("指纹数据为空");
            }

            List<String> houseIds = vo.getHouseIds();
            String cardNumber = vo.getCardNumber();
            String cardId = vo.getCardId();
            String fingerprint = vo.getFingerprint();

            for (String houseId : houseIds) {
                // 查询用户授权明细
                String sql = "SELECT la.* \n" +
                        "FROM saas_house_eligible_apply a\n" +
                        "JOIN saas_house_match_user u ON a.id = u.apply_id\n" +
                        "LEFT JOIN saas_smart_lock_auth la ON la.author_user_id = u.match_user_id  \n" +
                        "WHERE a.card_number = ? AND u.house_id = ? AND u.status = 1 AND la.bind_type = 0 \n" +
                        "UNION\n" +
                        "SELECT la.* \n" +
                        "FROM saas_house_eligible_apply_cohabit c\n" +
                        "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                        "LEFT JOIN saas_smart_lock_auth la ON la.author_user_id = c.id\n" +
                        "WHERE c.card_number = ? AND u.house_id = ? AND u.status = 1 AND la.bind_type = 0\n" +
                        "UNION \n" +
                        "SELECT la.*\n" +
                        "FROM saas_community_house_user u\n" +
                        "LEFT JOIN saas_smart_lock_auth la ON u.id = la.community_user_id\n" +
                        "WHERE u.card_number = ? AND u.community_house_id = ? AND u.status = 1 AND la.bind_type = 0 \n" +
                        "UNION \n" +
                        "SELECT la.*\n" +
                        "FROM saas_community_house_user u\n" +
                        "LEFT JOIN saas_app_user us ON u.mobile = us.phone\n" +
                        "LEFT JOIN saas_smart_lock_auth la ON u.id = la.community_user_id\n" +
                        "WHERE us.card_number = ? AND u.community_house_id = ? AND u.status = 1 AND la.bind_type = 0 ";
                List<Object> args = new ArrayList<>();
                args.add(cardNumber);
                args.add(houseId);
                args.add(cardNumber);
                args.add(houseId);
                args.add(cardNumber);
                args.add(houseId);
                args.add(cardNumber);
                args.add(houseId);

                // 授权智能锁
                List<SmartLockAuth> smartLockAuths = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(SmartLockAuth.class), args.toArray());
                if (!smartLockAuths.isEmpty()) {
                    SmartLockAuth smartLockAuth = smartLockAuths.get(0);
                    Long lockAuthId = smartLockAuth.getId();
                    Long lockId = smartLockAuth.getLockId();
                    StringBuffer msgBuf = new StringBuffer("");
                    if (cardId != null) {
                        // 授权身份证
                        ResultBean<Object> authCardResult = lockAppService.authCard(null, lockAuthId, lockId, 1, cardNumber, cardId, 1, null);
                        log.info("授权身份证结果, authCardResult={}", JSON.toJSONString(authCardResult));
                        if (!authCardResult.getCode().equals(StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                            log.info("授权身份证失败, authCardResult={}", JSON.toJSONString(authCardResult));
                            // 短信发送受限，不之间抛出异常
                            if (!authCardResult.getMsg().contains("短信通知失败")) {
                                return ResultBean.failedResultOfParamWithMsg(authCardResult.getMsg());
                            }
                            msgBuf.append(authCardResult.getMsg());
                        }
                    } else {
                        log.info("身份证id为空, 不支持身份证授权, cardNumber={}", cardNumber);
                    }

                    // 授权指纹
                    if (vo.getType() == 2) {
                        ResultBean<Object> fingerprintResult = lockAppService.authFingerprint(null, lockAuthId, lockId, 1, fingerprint, 1, null, false);
                        log.info("授权指纹结果, fingerprintResult={}", JSON.toJSONString(fingerprintResult));
                        if (!fingerprintResult.getCode().equals(StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                            if (StringUtils.isNotEmpty(msgBuf)) {
                                msgBuf.append("\t\n").append(fingerprintResult.getMsg());
                            } else {
                                msgBuf.append(fingerprintResult.getMsg());
                            }

                            // return ResultBean.failedResultOfParamWithMsg(fingerprintResult.getMsg() + msg );
                        }
                    }

                    if (StringUtils.isNotEmpty(msgBuf)) {
                        return ResultBean.failedResultOfParamWithMsg(msgBuf.toString());
                    }
                }
            }
            log.info("授权成功");
            return ResultBean.successfulResult(null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> verifyPhone(UserVO vo) {
        try {
            log.info("AioService verifyPhone vo={}", JSON.toJSONString(vo));
            if (StringUtils.isBlank(vo.getPhone())) {
                return ResultBean.failedResultOfParamWithMsg("手机号码为空");
            }
            if (StringUtils.isBlank(vo.getCode())) {
                return ResultBean.failedResultOfParamWithMsg("验证码为空");
            }
            String phone = vo.getPhone();
            String phoneCode = vo.getCode();

            String redisPhone = redisService.getSmsCodeMobile(phoneCode);
            if (!StringUtils.isBlank(redisPhone)) {
                if (redisPhone.equals(phone)) {
                    return ResultBean.successfulResult(null);
                } else {
                    return ResultBean.failedResultWithMsg("验证码不正确");
                }
            } else {
                return ResultBean.failedResultWithMsg("验证码未找到或已过期");
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> billVerifyUser(UserVO vo) {
        try {
            log.info("AioService billVerifyUser vo={}", JSON.toJSONString(vo));
            String cardNumber = vo.getCardNumber();
            String phone = vo.getPhone();

            Integer flag = null;// 标识：0未找到人员信息，1无账单，2有账单
            if (!StringUtils.isBlank(cardNumber)) {
                List<Map<String, Object>> data = (List<Map<String, Object>>) billList(vo).getResultData();
                if (CollectionUtils.isEmpty(data)) {
                    flag = 0;
                } else {
                    flag = 1;
                    for (Map<String, Object> map : data) {
                        List billData = (List) map.get("billData");
                        if (!CollectionUtils.isEmpty(billData)) {
                            flag = 2;
                            break;
                        }
                    }
                }
            }

            if (!StringUtils.isBlank(phone)) {
                List<Map<String, Object>> data = (List<Map<String, Object>>) billList(vo).getResultData();
                if (CollectionUtils.isEmpty(data)) {
                    flag = 0;
                } else {
                    flag = 1;
                    for (Map<String, Object> map : data) {
                        List billData = (List) map.get("billData");
                        if (!CollectionUtils.isEmpty(billData)) {
                            flag = 2;
                            break;
                        }
                    }
                }
            }

            return ResultBean.successfulResult(flag);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    /*public ResultBean<Object> billList(UserVO vo) {
        try {
            log.info("AioService billList vo={}", JSON.toJSONString(vo));
            String cardNumber = vo.getCardNumber();
            String phone = vo.getPhone();

            //查询用户关联房屋
            List<Map<String, Object>> houseList = new ArrayList<>();
            if (StringUtils.isNotBlank(cardNumber)) {
                String houseSql = "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType\n" +
                        "FROM saas_house_eligible_apply a\n" +
                        "JOIN saas_house_match_user u ON a.id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE a.card_number = ? AND u.status = 1\n" +
                        "UNION\n" +
                        "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType \n" +
                        "FROM saas_house_eligible_apply_cohabit c\n" +
                        "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE c.card_number = ? AND u.status = 1\n" +
                        "UNION\n" +
                        "SELECT u.community_house_id AS houseId,h.house_nature houseNature,h.house_property_id AS orgId,dh.merchants_type AS merchantsType  \n" +
                        "FROM saas_community_house_user u\n" +
                        "LEFT JOIN saas_app_user us ON us.phone = u.mobile\n" +
                        "LEFT JOIN saas_house h ON u.community_house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.house_property_id = dh.org_id\n" +
                        "WHERE us.card_number = ? AND u.status = 1";
                List<Object> args = new ArrayList<>();
                args.add(cardNumber);
                args.add(cardNumber);
                args.add(cardNumber);
                houseList = jdbcTemplate.queryForList(houseSql, args.toArray());
            }

            if (StringUtils.isNotBlank(phone)) {
                String houseSql = "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType\n" +
                        "FROM saas_house_eligible_apply a\n" +
                        "JOIN saas_house_match_user u ON a.id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE a.mobile = ? AND u.status = 1 \n" +
                        "UNION\n" +
                        "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType \n" +
                        "FROM saas_house_eligible_apply_cohabit c\n" +
                        "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE c.mobile = ? AND u.status = 1 \n" +
                        "UNION\n" +
                        "SELECT u.community_house_id AS houseId,h.house_nature houseNature,h.house_property_id AS orgId,dh.merchants_type AS merchantsType  \n" +
                        "FROM saas_community_house_user u\n" +
                        "LEFT JOIN saas_house h ON u.community_house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.house_property_id = dh.org_id\n" +
                        "WHERE u.mobile = ? AND u.status = 1";
                List<Object> args = new ArrayList<>();
                args.add(phone);
                args.add(phone);
                args.add(phone);
                houseList = jdbcTemplate.queryForList(houseSql, args.toArray());
            }

            List<Map<String, Object>> data = new ArrayList<>();
            for (Map<String, Object> houseMap : houseList) {
                Map<String, Object> map = new HashMap<>();
                String houseId = houseMap.get("houseId").toString();
                Integer houseNature = Integer.parseInt(houseMap.get("houseNature").toString());
                Long orgId = Long.parseLong(houseMap.get("orgId").toString());
                Integer merchantsType = Integer.parseInt(houseMap.get("merchantsType").toString());

                map.put("houseId", houseId);
                map.put("houseNature", houseNature);
                map.put("orgId", orgId);
                map.put("merchantsType", merchantsType);
                HouseInfoVO houseInfoVO = houseService.findHouse(houseId).getResultData();
                map.put("houseInfo", houseInfoVO.getResidenceCommunityName() + houseInfoVO.getBuildingNumName() + "栋"
                        + houseInfoVO.getUnitName() + "单元" + houseInfoVO.getRoomNumber() + "号");

                String sql = "";
                if (houseNature == 1) {
                    sql = "SELECT id,if(charge_type = 1,8,9) AS chargeType,start_time AS startTime,end_time AS endTime,cost \n" +
                            "FROM saas_rent_bill \n" +
                            "WHERE house_id = ? AND audit_status = 1 AND payment_status = 0\n" +
                            "UNION ALL\n" +
                            "SELECT id,charge_type AS chargeType,start_time AS startTime,end_time AS endTime,cost \n" +
                            "FROM saas_expense_bill \n" +
                            "WHERE house_id = ? AND audit_status = 1 AND payment_status = 0";
                } else {
                    sql = "SELECT id,if(charge_type = 1,8,9) AS chargeType,start_time AS startTime,end_time AS endTime,cost \n" +
                            "FROM saas_estate_rent_bill \n" +
                            "WHERE house_id = ? AND audit_status = 1 AND payment_status = 0\n" +
                            "UNION ALL\n" +
                            "SELECT id,charge_type AS chargeType,start_time AS startTime,end_time AS endTime,cost \n" +
                            "FROM saas_estate_expense_bill \n" +
                            "WHERE house_id = ? AND audit_status = 1 AND payment_status = 0";
                }
                List<BillVO> billData = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BillVO.class), houseId, houseId);
                for (BillVO billVO : billData) {
                    billVO.setStartTime(DateUtils.format(billVO.getStartTime(), DateUtils.FORMAT_DATE_8, DateUtils.FORMAT_DATE_8));
                    billVO.setEndTime(DateUtils.format(billVO.getEndTime(), DateUtils.FORMAT_DATE_8, DateUtils.FORMAT_DATE_8));
                    billVO.setCost(ConvertUtils.fen2yuan(Integer.parseInt(billVO.getCost().toString())));
                }
                map.put("billData", billData);

                data.add(map);
            }

            return ResultBean.successfulResult(data);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }*/

    public ResultBean<Object> billList(UserVO vo) {
        try {
            log.info("AioService billList vo={}", JSON.toJSONString(vo));
            String cardNumber = vo.getCardNumber();
            String phone = vo.getPhone();

            // 查询用户关联房屋
            List<Map<String, Object>> houseList = new ArrayList<>();
            if (StringUtils.isNotBlank(cardNumber)) {
                String houseSql = "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType\n" +
                        "FROM saas_house_eligible_apply a\n" +
                        "JOIN saas_house_match_user u ON a.id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE a.card_number = ? AND u.status = 1\n" +
                        "UNION\n" +
                        "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType \n" +
                        "FROM saas_house_eligible_apply_cohabit c\n" +
                        "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE c.card_number = ? AND u.status = 1\n" +
                        "UNION\n" +
                        "SELECT u.community_house_id AS houseId,h.house_nature houseNature,h.house_property_id AS orgId,dh.merchants_type AS merchantsType  \n" +
                        "FROM saas_community_house_user u\n" +
                        "LEFT JOIN saas_house h ON u.community_house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.house_property_id = dh.org_id\n" +
                        "WHERE u.card_number = ? AND u.status = 1";
                List<Object> args = new ArrayList<>();
                args.add(cardNumber);
                args.add(cardNumber);
                args.add(cardNumber);
                houseList = jdbcTemplate.queryForList(houseSql, args.toArray());
            }

            if (StringUtils.isNotBlank(phone)) {
                String houseSql = "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType\n" +
                        "FROM saas_house_eligible_apply a\n" +
                        "JOIN saas_house_match_user u ON a.id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE a.mobile = ? AND u.status = 1 \n" +
                        "UNION\n" +
                        "SELECT u.house_id AS houseId,h.house_nature houseNature,h.org_id AS orgId,dh.merchants_type AS merchantsType \n" +
                        "FROM saas_house_eligible_apply_cohabit c\n" +
                        "JOIN saas_house_match_user u ON c.apply_id = u.apply_id\n" +
                        "LEFT JOIN saas_house h ON u.house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.org_id = dh.org_id\n" +
                        "WHERE c.mobile = ? AND u.status = 1 \n" +
                        "UNION\n" +
                        "SELECT u.community_house_id AS houseId,h.house_nature houseNature,h.house_property_id AS orgId,dh.merchants_type AS merchantsType  \n" +
                        "FROM saas_community_house_user u\n" +
                        "LEFT JOIN saas_house h ON u.community_house_id = h.id\n" +
                        "LEFT JOIN saas_department_hierarchy dh ON h.house_property_id = dh.org_id\n" +
                        "WHERE u.mobile = ? AND u.status = 1";
                List<Object> args = new ArrayList<>();
                args.add(phone);
                args.add(phone);
                args.add(phone);
                houseList = jdbcTemplate.queryForList(houseSql, args.toArray());
            }

            List<Map<String, Object>> data = new ArrayList<>();
            for (Map<String, Object> houseMap : houseList) {
                Map<String, Object> map = new HashMap<>();
                String houseId = houseMap.get("houseId").toString();
                Integer houseNature = Integer.parseInt(houseMap.get("houseNature").toString());
                Long orgId = Long.parseLong(houseMap.get("orgId").toString());
                Integer merchantsType = Integer.parseInt(houseMap.get("merchantsType").toString());

                map.put("houseId", houseId);
                map.put("houseNature", houseNature);
                map.put("orgId", orgId);
                map.put("merchantsType", merchantsType);
                HouseInfoVO houseInfoVO = houseService.findHouse(houseId).getResultData();
                map.put("houseInfo", houseInfoVO.getResidenceCommunityName() + houseInfoVO.getBuildingNumName() + "栋"
                        + houseInfoVO.getUnitName() + "单元" + houseInfoVO.getRoomNumber() + "号");

                String sql = "";
                List<BillVO> billData;
                if (houseNature == 1) {
                    // type 1公租房 2房产
                    sql = "SELECT b.id,IF(b.charge_type = 1,8,9) AS chargeType,b.start_time AS startTime,b.end_time AS endTime,b.cost,b.org_id AS orgId,dh.merchants_type AS merchantsType,1 as type \n" +
                            "FROM saas_rent_bill b\n" +
                            "LEFT JOIN saas_department_hierarchy dh ON b.org_id = dh.org_id\n" +
                            "WHERE b.house_id = ? AND b.audit_status = 1 AND b.payment_status = 0\n" +
                            "UNION ALL\n" +
                            "SELECT b.id,b.charge_type AS chargeType,b.start_time AS startTime,b.end_time AS endTime,b.cost,b.org_id AS orgId,dh.merchants_type AS merchantsType,1 as type \n" +
                            "FROM saas_expense_bill b\n" +
                            "LEFT JOIN saas_department_hierarchy dh ON b.org_id = dh.org_id \n" +
                            "WHERE house_id = ? AND audit_status = 1 AND payment_status = 0\n" +
                            "UNION ALL\n" +
                            "SELECT b.id,IF(b.charge_type = 1,8,9) AS chargeType,b.start_time AS startTime,b.end_time AS endTime,b.cost,b.org_id AS orgId,dh.merchants_type AS merchantsType,2 as type\n" +
                            "FROM saas_estate_rent_bill b\n" +
                            "LEFT JOIN saas_department_hierarchy dh ON b.org_id = dh.org_id\n" +
                            "WHERE b.house_id = ? AND b.audit_status = 1 AND b.payment_status = 0\n" +
                            "UNION ALL\n" +
                            "SELECT b.id,b.charge_type AS chargeType,b.start_time AS startTime,b.end_time AS endTime,b.cost,b.org_id AS orgId,dh.merchants_type AS merchantsType,2 as type\n" +
                            "FROM saas_estate_expense_bill b\n" +
                            "LEFT JOIN saas_department_hierarchy dh ON b.org_id = dh.org_id\n" +
                            "WHERE house_id = ? AND audit_status = 1 AND payment_status = 0";
                    billData = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BillVO.class), houseId, houseId, houseId, houseId);
                } else {
                    sql = "SELECT b.id,IF(b.charge_type = 1,8,9) AS chargeType,b.start_time AS startTime,b.end_time AS endTime,b.cost,b.org_id AS orgId,dh.merchants_type AS merchantsType,2 as type\n" +
                            "FROM saas_estate_rent_bill b\n" +
                            "LEFT JOIN saas_department_hierarchy dh ON b.org_id = dh.org_id\n" +
                            "WHERE b.house_id = ? AND b.audit_status = 1 AND b.payment_status = 0\n" +
                            "UNION ALL\n" +
                            "SELECT b.id,b.charge_type AS chargeType,b.start_time AS startTime,b.end_time AS endTime,b.cost,b.org_id AS orgId,dh.merchants_type AS merchantsType,2 as type\n" +
                            "FROM saas_estate_expense_bill b\n" +
                            "LEFT JOIN saas_department_hierarchy dh ON b.org_id = dh.org_id \n" +
                            "WHERE house_id = ? AND audit_status = 1 AND payment_status = 0";
                    billData = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(BillVO.class), houseId, houseId);
                }
                for (BillVO billVO : billData) {
                    billVO.setStartTime(DateUtils.format(billVO.getStartTime(), DateUtils.FORMAT_DATE_8, DateUtils.FORMAT_DATE_8));
                    billVO.setEndTime(DateUtils.format(billVO.getEndTime(), DateUtils.FORMAT_DATE_8, DateUtils.FORMAT_DATE_8));
                    billVO.setCost(ConvertUtils.fen2yuan(Integer.parseInt(billVO.getCost().toString())));
                }
                map.put("billData", billData);
                if(CollectionUtils.isEmpty(billData)){
                    continue;
                }
                data.add(map);
            }

            return ResultBean.successfulResult(data);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Map<String, Object>> payment(AioPaymentVO vo) {
        try {
            log.info("AioService payment vo={}", JSON.toJSONString(vo));

            if (CollectionUtils.isEmpty(vo.getRentIds()) && CollectionUtils.isEmpty(vo.getExpenseIds())
                    && CollectionUtils.isEmpty(vo.getEstateRentIds()) && CollectionUtils.isEmpty(vo.getEstateExpenseIds())) {
                return ResultBean.failedResultOfParamWithMsg("参数错误");
            }

            if (vo.getPaymentType() == null || vo.getChargeType() == null) {
                return ResultBean.failedResultOfParamWithMsg("参数错误");
            }

            if (!PaymentTypeEnum.operate(vo.getPaymentType()) || !ChargeTypeEnum.operate(vo.getChargeType())) {
                return ResultBean.failedResultOfParamWithMsg("参数错误");
            }

            if (StringUtils.isBlank(vo.getCardNumber()) && StringUtils.isBlank(vo.getPhone())) {
                return ResultBean.failedResultOfParamWithMsg("参数错误");
            }


            String userId = null;
            if (!StringUtils.isBlank(vo.getCardNumber())) {
                AppUser appUser = appUserRepository.findByCardNumber(vo.getCardNumber());
                if (appUser != null) {
                    userId = appUser.getId();
                }
            }
            if (!StringUtils.isBlank(vo.getPhone())) {
                AppUser appUser = appUserRepository.findByPhone(vo.getPhone());
                if (appUser != null) {
                    userId = appUser.getId();
                }
            }

            Integer cose = 0;
            Long orgId = null;
            String matchUserId = null;
            List<RentBill> rentBills = new ArrayList<>();
            List<ExpenseBill> expenseBills = new ArrayList<>();
            List<EstateRentBill> estateRentBills = new ArrayList<>();
            List<EstateExpenseBill> estateExpenseBills = new ArrayList<>();
            if (!CollectionUtils.isEmpty(vo.getRentIds())) {
                rentBills = rentBillRepository.findByIdIn(vo.getRentIds());
            }
            if (!CollectionUtils.isEmpty(vo.getExpenseIds())) {
                expenseBills = expenseBillRepository.findByIdIn(vo.getExpenseIds());
            }
            if (!CollectionUtils.isEmpty(vo.getEstateRentIds())) {
                estateRentBills = estateRentBillRepository.findByIdIn(vo.getEstateRentIds());
            }
            if (!CollectionUtils.isEmpty(vo.getEstateExpenseIds())) {
                estateExpenseBills = estateExpenseBillRepository.findByIdIn(vo.getEstateExpenseIds());
            }

            if (CollectionUtils.isEmpty(rentBills) && CollectionUtils.isEmpty(expenseBills)
                    && CollectionUtils.isEmpty(estateRentBills) && CollectionUtils.isEmpty(estateExpenseBills)) {
                log.warn("AioService payment 未找到费用明细 rentIds={},expenseIds={},estateRentIds={},estateExpenseIds={}",
                        vo.getRentIds(), vo.getExpenseIds(), vo.getEstateRentIds(), vo.getEstateExpenseIds());
                return ResultBean.failedResultWithMsg("未找到费用明细，请重试");
            }

            for (RentBill rentBill : rentBills) {
                if (rentBill.getPaymentStatus() == RrentBillPaymentStatusTypeEnum.PAY.getValue()) {
                    log.warn("AioService payment 此费用已支付,无需重复支付 id={},houseId={}", rentBill.getId(), rentBill.getHouseId());
                    return ResultBean.failedResultWithMsg("当前有费用已支付,无需重复支付");
                }
                cose += rentBill.getCost();
            }
            for (ExpenseBill expenseBill : expenseBills) {
                if (expenseBill.getPaymentStatus() == RrentBillPaymentStatusTypeEnum.PAY.getValue()) {
                    log.warn("AioService payment 此费用已支付,无需重复支付 id={},houseId={}", expenseBill.getId(), expenseBill.getHouseId());
                    return ResultBean.failedResultWithMsg("当前有费用已支付,无需重复支付");
                }
                cose += expenseBill.getCost();
            }
            for (EstateRentBill estateRentBill : estateRentBills) {
                if (estateRentBill.getPaymentStatus() == RrentBillPaymentStatusTypeEnum.PAY.getValue()) {
                    log.warn("AioService payment 此费用已支付,无需重复支付 id={},houseId={}", estateRentBill.getId(), estateRentBill.getHouseId());
                    return ResultBean.failedResultWithMsg("当前有费用已支付,无需重复支付");
                }
                cose += estateRentBill.getCost();
            }
            for (EstateExpenseBill estateExpenseBill : estateExpenseBills) {
                if (estateExpenseBill.getPaymentStatus() == RrentBillPaymentStatusTypeEnum.PAY.getValue()) {
                    log.warn("AioService payment 此费用已支付,无需重复支付 id={},houseId={}", estateExpenseBill.getId(), estateExpenseBill.getHouseId());
                    return ResultBean.failedResultWithMsg("当前有费用已支付,无需重复支付");
                }
                cose += estateExpenseBill.getCost();
            }

            if (!CollectionUtils.isEmpty(rentBills)) {
                orgId = rentBills.get(0).getOrgId();
                matchUserId = rentBills.get(0).getMatchUserId();
            }
            if (!CollectionUtils.isEmpty(expenseBills)) {
                orgId = expenseBills.get(0).getOrgId();
                matchUserId = expenseBills.get(0).getMatchUserId();
            }
            if (!CollectionUtils.isEmpty(estateRentBills)) {
                orgId = estateRentBills.get(0).getOrgId();
                matchUserId = estateRentBills.get(0).getMatchUserId();
            }
            if (!CollectionUtils.isEmpty(estateExpenseBills)) {
                orgId = estateExpenseBills.get(0).getOrgId();
                matchUserId = estateExpenseBills.get(0).getMatchUserId();
            }

            // 手续费比例
            String platStr = redisService.getValue("platform.commission");
            BigDecimal totalAmount = DataUtils.IntegerToBigdecimal(cose);
            Integer plat = 0;
            if (StringUtils.isNotBlank(platStr)) {
                BigDecimal platform = DataUtils.IntegerToBigdecimal(Integer.valueOf(platStr));
                BigDecimal platAmount = totalAmount.multiply(platform).setScale(2, BigDecimal.ROUND_HALF_UP);
                totalAmount = totalAmount.add(platAmount).setScale(2, BigDecimal.ROUND_HALF_UP);
                plat = DataUtils.doubleToInteger(platAmount.doubleValue());
            }

            PaymentBillRedisVo redisVo = new PaymentBillRedisVo();
            redisVo.setOrgId(orgId);
            redisVo.setPaymentStatus(0);
            redisVo.setPlat(plat);
            if (StringUtils.isNotBlank(userId)) {
                redisVo.setUserId(userId);
            } else {
                redisVo.setUserId(matchUserId);
            }
            String outTradeNo = String.valueOf(KeyWorker.nextId());
            redisVo.setOutTradeNo(outTradeNo);
            redisVo.setIds(vo.getRentIds());
            redisVo.setExpenseIds(vo.getExpenseIds());
            redisVo.setEstateRentIds(vo.getEstateRentIds());
            redisVo.setEstateExpenseIds(vo.getEstateExpenseIds());
            redisVo.setTotalAmount(totalAmount);
            redisVo.setBusinessType(8);// 一体机扫码支付

            // 操作用户企业信息
            DepartmentHierarchy departmentHierarchy = departmentHierarchyService.getEnterpriseInfo(orgId);
            if (departmentHierarchy == null) {
                log.warn("AioService payment 企业信息错误 orgId={}", orgId);
                return ResultBean.failedResultWithMsg("企业信息错误");
            }

            // 支付方式
            if (vo.getPaymentType() == PaymentTypeEnum.WECHAT.getValue()) {
                WechatAccount account = null;
                // 根据企业设置, 获取收款方式(平台收款, 企业商户号收款)
                // 收款方式：0平台商户号收款 1企业商户号收款
                if (departmentHierarchy.getMerchantsType() == 0) {
                    // 0为平台收款商户号企业id
                    account = wechatAccountRepository.findByOrgIdAndType(0L, PaymentTypeEnum.WECHAT.getValue());
                } else {
                    // 默认使用企业账户号收款
                    account = wechatAccountRepository.findByOrgIdAndType(orgId, PaymentTypeEnum.WECHAT.getValue());
                }

                if (account == null) {
                    log.warn("AioService payment 未找到微信商户配置,请联系负责人orgId={}", orgId);
                    return ResultBean.failedResultWithMsg("未找到微信商户配置,请联系客服");
                }

                // 应用ID或者分配的appId
                String appId = redisService.getValue(Constant.WX_APPID);
                String attac = outTradeNo;
                String spbillCreateIp = redisService.getValue(Constant.SPBILL_CREATE_IP);
                String body = "房屋管家-" + ChargeTypeEnum.getText(vo.getChargeType());
                cose = DataUtils.doubleToInteger(totalAmount.doubleValue());
                WxPay wxpay = new WxPay(appId, account.getMchId(), outTradeNo, attac, cose, body,
                        account.getMchApiKey(), null, payConfig.getWxNotifyUrl(), payConfig.getUnifiedApi(), spbillCreateIp);
                Map<String, Object> result = new WxPayRequest(wxpay).unifiedByNative();
                if (result == null) {
                    return ResultBean.failedResultWithMsg("微信支付异常,请联系客服");
                }
                redisVo.setMchApiKey(account.getMchApiKey());
                redisVo.setMerchantId(account.getId());
                redisVo.setMerchantsType(departmentHierarchy.getMerchantsType());
                redisService.putPaymentBill(redisVo);
                return ResultBean.successfulResult(result);
            }

            if (vo.getPaymentType() == PaymentTypeEnum.ALI.getValue()) {
                WechatAccount account = null;
                // 收款方式：0平台商户号收款 1企业商户号收款
                if (departmentHierarchy.getMerchantsType() == 0) {
                    // 0为平台收款商户号企业id
                    account = wechatAccountRepository.findByOrgIdAndType(0L, PaymentTypeEnum.ALI.getValue());
                } else {
                    // 默认使用企业账户号收款
                    account = wechatAccountRepository.findByOrgIdAndType(orgId, PaymentTypeEnum.ALI.getValue());
                }

                if (account == null) {
                    log.warn("AioService payment 未找到支付宝配置,请联系负责人 orgId={}", orgId);
                    return ResultBean.failedResultWithMsg("未找到支付宝配置,请联系负责人");
                }

                String subject = ChargeTypeEnum.getText(vo.getChargeType());
                String passbackParams = outTradeNo;

                AliPay alipay = new AliPay(account.getMchId(), account.getPrivateKey(), account.getPublicKey(),
                        outTradeNo, totalAmount.toString(), subject, "QUICK_MSECURITY_PAY", passbackParams,
                        payConfig.getAliNotifyUrl());

                Map<String, Object> result = new AliPayRequest(alipay).scanPay();

                if (result == null) {
                    return ResultBean.failedResultWithMsg("支付宝支付异常,请联系客服");
                }
                redisVo.setPublicKey(account.getPublicKey());
                redisVo.setMerchantId(account.getId());
                redisVo.setMerchantsType(departmentHierarchy.getMerchantsType());
                redisService.putPaymentBill(redisVo);
                return ResultBean.successfulResult(result);
            }

            return ResultBean.failedResultOfParamWithMsg("参数错误");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Map<String, Object>> orderQuery(OrderQueryVO vo) {
        try {
            log.info("AioService orderQuery vo={}", JSON.toJSONString(vo));

            if (vo.getPaymentType() == null) {
                return ResultBean.failedResultOfParamWithMsg("支付类型为空");
            }
            if (StringUtils.isBlank(vo.getOutTradeNo())) {
                return ResultBean.failedResultOfParamWithMsg("商户订单号为空");
            }
            if (StringUtils.isBlank(vo.getMchid())) {
                return ResultBean.failedResultOfParamWithMsg("商户号为空");
            }
            if (vo.getPaymentType() == 1 && StringUtils.isBlank(vo.getMchApiKey())) {
                return ResultBean.failedResultOfParamWithMsg("API密钥为空");
            }
            if (vo.getPaymentType() == 2 && StringUtils.isBlank(vo.getPublicKey())) {
                return ResultBean.failedResultOfParamWithMsg("支付宝公钥为空");
            }
            if (vo.getPaymentType() == 2 && StringUtils.isBlank(vo.getPrivateKey())) {
                return ResultBean.failedResultOfParamWithMsg("支付宝密钥为空");
            }

            // 支付方式
            if (vo.getPaymentType() == PaymentTypeEnum.WECHAT.getValue()) {
                // 应用ID或者分配的appId
                String appId = redisService.getValue(Constant.WX_APPID);

                WxPay wxpay = new WxPay(appId, vo.getMchid(), vo.getOutTradeNo(), null, null, null,
                        vo.getMchApiKey(), null, null, payConfig.getOrderQueryUrl(), null);
                Map<String, Object> result = new WxPayRequest(wxpay).orderQuery();
                if (result == null) {
                    return ResultBean.failedResultWithMsg("微信查询订单异常,请联系客服");
                }

                return ResultBean.successfulResult(result);
            }

            if (vo.getPaymentType() == PaymentTypeEnum.ALI.getValue()) {
                AliPay alipay = new AliPay(vo.getMchid(), vo.getPrivateKey(), vo.getPublicKey(),
                        vo.getOutTradeNo(), null, null, null, null, null);

                Map<String, Object> result = new AliPayRequest(alipay).orderQuery();

                if (result == null) {
                    return ResultBean.failedResultWithMsg("支付宝询订单异常,请联系客服");
                }

                return ResultBean.successfulResult(result);
            }

            return ResultBean.failedResultOfParamWithMsg("参数错误");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    public ResultBean<Object> findDevicePwd(String number) {
        try {
            if (StringUtils.isBlank(number)) {
                return ResultBean.failedResultOfParamWithMsg("设备编号为空");
            }

            String value = redisService.getValue("aio.pwd");

            List<Device> devices = deviceRepository.findByNumberAndDelStatus(number, 0);
            if (!devices.isEmpty()) {
                Device device = devices.get(0);
                DeviceVO vo = new DeviceVO();
                BeanUtils.copyProperties(device, vo);
                if (StringUtils.isNotBlank(device.getPwd())) {
                    String pwd = new String(Base64Utils.decode(device.getPwd()));
                    vo.setPwd(pwd);
                } else {
                    vo.setPwd(value);
                }
                return ResultBean.successfulResult(vo);
            } else {
                DeviceVO vo = new DeviceVO();
                vo.setPwd(value);
                return ResultBean.successfulResult(vo);
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }


    public ResultBean<Object> houseListV2(AuthVO vo) {
        String certNumber = vo.getCardNumber();
        List<Map<String, Object>> list = new ArrayList<>();
        if (StringUtils.isBlank(certNumber)) {
            return ResultBean.failedResultOfParamWithMsg("身份证号为空");

        }
        List<CommunityHouseUser> communityHouseUsers = communityHouseUserRepository.findByCardNumberAndStatus(certNumber, 1);
        if (CollectionUtils.isEmpty(communityHouseUsers)) {
            return ResultBean.successfulResult(list);
        }

        List<String> houseIds = communityHouseUsers.stream().map(CommunityHouseUser::getCommunityHouseId).distinct().collect(Collectors.toList());

        for (String houseId : houseIds) {
            Map<String, Object> map = new HashMap<>();
            Optional<House> byId = houseRepository.findById(houseId);
            if (!byId.isPresent()) {
                continue;
            }
            House house = byId.get();

            List<SmartLock> smartLock = smartLockRepository.findByHouseId(houseId);
            if (CollectionUtils.isEmpty(smartLock)) {
                continue;
            }

            Long brandId = smartLock.get(0).getBrandId();
            if (brandId == 5 || brandId == 6) {
                // 人脸
                map.put("authMode", SmartLock.AUTH_MODE_FACE);
            } else {
                // 指纹
                map.put("authMode", SmartLock.AUTH_MODE_FINGERPRINT);
            }


            // 构建房屋全路径参数
            String housePath = communityHouseUserService.buildHousePath(house);
            map.put("address", housePath + house.getRoomNumber());
            map.put("houseId", houseId);
            CommunityHouseUser cardNumber = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndCardNumber(houseId, 1, certNumber);
            map.put("communityHouseUserId", cardNumber.getId());
            list.add(map);
        }

        return ResultBean.successfulResult(list);
    }

    public ResultBean<Object> lockFaceAuth(AuthVO vo) {

        String houseId = vo.getHouseId();
        Long communityHouseUserId = vo.getCommunityHouseUserId();
        Integer authMode = vo.getAuthMode();

        Optional<House> houseOptional = houseRepository.findById(houseId);
        if (!houseOptional.isPresent()) {
            return ResultBean.failedResultWithMsg("房屋不存在");
        }
        House house = houseOptional.get();

        SmartLock smartLock = smartLockRepository.findByHouseIdAnAndBrandId(houseId);
        if (ObjectUtil.isNull(smartLock)) {
            return ResultBean.failedResultWithMsg("房屋未绑锁");
        }

        Optional<CommunityHouseUser> byId = communityHouseUserRepository.findById(communityHouseUserId);
        if (!byId.isPresent()) {
            return ResultBean.failedResultWithMsg("用户未绑定");
        }
        CommunityHouseUser communityHouseUser = byId.get();

        String faceImageUrl = communityHouseUser.getHumanFaceImage();
        if (StrUtil.isEmpty(faceImageUrl)) {
            Optional<AppUser> byId1 = appUserRepository.findById(communityHouseUser.getUserId());
            if (byId1.isPresent()) {
                AppUser appUser = byId1.get();
                faceImageUrl = appUser.getFacePic();
            }
        }


        SmartLockAuth smartLockAuth = smartLockAuthRepository.findByHouseIdAndCommunityUserId(houseId, communityHouseUserId);
        Long authId = smartLockAuth.getId();
        Long lockId = smartLockAuth.getLockId();
        if (authMode.equals(SmartLock.AUTH_MODE_FACE)) {
            // 授权人脸

            SmartLockFace smartLockFace = new SmartLockFace();
            smartLockFace.setFaceImage("https://xj-saas-images.oss-cn-qingdao.aliyuncs.com/"+faceImageUrl);
            smartLockFace.setLockId(smartLockAuth.getLockId());

            smartLockFace.setLockAuthId(smartLockAuth.getId());
            smartLockFace.setAuthType(SmartLockFace.PERMANENT_FLAG_YES);
            ResultBean<Object> resultBean = lockAppService.authFace(null, smartLockFace);
            String code = resultBean.getCode();
            if (!StringUtils.equals(code, StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                log.error("授权人脸失败, resultBean={}", JSON.toJSONString(resultBean));
                return ResultBean.failedResult("人脸授权失败");
            }
        } else if (authMode.equals(SmartLock.AUTH_MODE_FINGERPRINT)) {
            String cardId = vo.getCardId();
            String cardNumber = vo.getCardNumber();
            String fingerprint = vo.getFingerprint();

            if (StrUtil.isEmpty(cardId) || StrUtil.isEmpty(cardNumber) || StrUtil.isEmpty(fingerprint)) {
                return ResultBean.failedResultOfParamWithMsg("参数错误");
            }

            // 授权指纹
            StringBuffer msgBuf = new StringBuffer();
            // 授权身份证
            ResultBean<Object> authCardResult = lockAppService.authCard(null, authId, lockId, 1, cardNumber, cardId, 1, null);
            log.info("授权身份证结果, authCardResult={}", JSON.toJSONString(authCardResult));
            if (!authCardResult.getCode().equals(StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                log.info("授权身份证失败, authCardResult={}", JSON.toJSONString(authCardResult));
                // 短信发送受限，不之间抛出异常
                if (!authCardResult.getMsg().contains("短信通知失败")) {
                    return ResultBean.failedResultOfParamWithMsg(authCardResult.getMsg());
                }
                msgBuf.append(authCardResult.getMsg());
            }


            ResultBean<Object> fingerprintResult = lockAppService.authFingerprint(null, authId, lockId, 1, fingerprint, 1, null, false);
            log.info("授权指纹结果, fingerprintResult={}", JSON.toJSONString(fingerprintResult));
            if (!fingerprintResult.getCode().equals(StatusCode.SUCCESS_CODE_10000.getErrorCode())) {
                if (StringUtils.isNotEmpty(msgBuf)) {
                    msgBuf.append("\t\n").append(fingerprintResult.getMsg());
                } else {
                    msgBuf.append(fingerprintResult.getMsg());
                }
            }
            if (StringUtils.isNotEmpty(msgBuf)) {
                return ResultBean.failedResult(msgBuf.toString());
            }

        }
        return ResultBean.successfulResult(null);
    }

    public ResultBean<Object> authVerify(AuthenticationVo vo){
        long start = System.currentTimeMillis();
        if (StrUtil.isEmpty(vo.getFaceData())|| StrUtil.isEmpty( vo.getCardData())) {
            return ResultBean.failedResultOfParamWithMsg("参数错误");
        }
        Boolean flag = faceThanService.FaceCompareFace(vo.getFaceData(), vo.getCardData());
        log.info("人脸识别耗时:{}",System.currentTimeMillis() - start);
        if (!flag){
            return ResultBean.failedResult("当前照片与身份证不匹配");
        }

        log.info("身份验证耗时:{}",System.currentTimeMillis() - start);
        return ResultBean.successfulResult("当前照片与身份证匹配");
    }


    public ResultBean<Object> updateAuthInfo(AuthenticationVo vo) {

        String certName = vo.getCertName();
        String certNumber = vo.getCertNumber();
        String ossIdFaceUrl = vo.getOssIdFaceUrl();
        if (StrUtil.isEmpty(certName) || StrUtil.isEmpty(certNumber) || StrUtil.isEmpty(ossIdFaceUrl)) {
            return ResultBean.failedResultOfParamWithMsg("参数错误");
        }
        String faceUrl = ossIdFaceUrl.split("https://xj-saas-images.oss-cn-qingdao.aliyuncs.com/")[1];

        List<CommunityHouseUser> communityHouseUsers = communityHouseUserRepository.findByCardNumber(certNumber);
        if (!CollectionUtils.isEmpty(communityHouseUsers)){
            communityHouseUsers.forEach(m-> {

                m.setHumanFaceImage(faceUrl);
                m.setCardNumber(certNumber);
                m.setName(certName);
            });
            communityHouseUserRepository.saveAll(communityHouseUsers);

            AppUser appUser = appUserRepository.findByCardNumberAndPhone(certNumber,communityHouseUsers.get(0).getMobile());
            if (appUser == null ){
                appUser = new AppUser();
                byte[] salt = Digests.generateSalt(8);
                String saltStr = Encodes.encodeHex(salt);;
                appUser.setId("S" + KeyWorker.nextId());
                appUser.setPassword(null);
                appUser.setPhone(communityHouseUsers.get(0).getMobile());
                appUser.setSalt(saltStr);
                appUser.setType(3);// 小程序用户
                appUser.setStatus(1);
                appUser.setRegistrationTime(new Date());
            }
            appUser.setCertificationStatus(1);
            appUser.setName(certName);
            appUser.setCardNumber(certNumber);
            appUser.setFacePic(faceUrl);

            appUserRepository.save(appUser);
        }else {
            return ResultBean.failedResult("未找到用户");
        }
        return  ResultBean.successfulResult("更新成功");
    }
}
